home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-04-07 | 36.4 KB | 1,000 lines | [TEXT/CWIE] |
-
- //
- // ExceptionPPC.cp - Exception Handling Runtime Support for CodeWarriorâ„¢ (PowerPC)
- //
- // Copyright © 1995 metrowerks inc. All rights reserved.
- //
- //
- // POWERPC STACK FRAME FORMAT
- //
- // The PowerPC runtime architecture uses a grow-down stack with a single stack
- // pointer at the low address end. The stack has the following organization:
- //
- //
- // LOW ADDRESSES | |
- // | |
- // |-----------------------|
- // | GPR save area |
- // |-----------------------| Can be used by frameless leaf routines
- // | FPR save area |
- // Callee's SP =>|-----------------------|
- // | Callee's |
- // | linkage area |
- // |-----------------------|
- // | Callee's | Storage for parameters passed to
- // | parameter area | routines called by callee
- // |-----------------------|
- // | Callee's |
- // | local variables |
- // |-----------------------|
- // | alignment gap 1 |
- // |-----------------------|
- // | GPR save area | Storage for nonvolatile GPRs used by callee
- // |-----------------------|
- // | alignment gap 2 |
- // |-----------------------|
- // | FPR save area | Storage for nonvolatile FPRs used by callee
- // Caller's SP =>|-----------------------|
- // | Caller's |
- // | linkage area |
- // |-----------------------|
- // | Caller's | Storage for parameters passed to
- // | parameter area | callee
- // |-----------------------|
- // | Caller's |
- // | local variables |
- // |-----------------------|
- // | |
- // HIGH ADDRESSES | |
- //
- //
- // where the "linkage area" looks like this:
- //
- //
- // |-----------------------|
- // 0 | Stack Frame Back Link | Pointer to caller's frame
- // |-----------------------|
- // 4 | Saved CR | Our CR (saved by routines we call)
- // |-----------------------|
- // 8 | Saved LR | Our LR (saved by routines we call)
- // |-----------------------|
- // 12 | (Reserved) |
- // |-----------------------|
- // 16 | (Reserved) |
- // |-----------------------|
- // 20 | Saved TOC Pointer | Our TOC (saved by cross-TOC glue)
- // |-----------------------|
- //
- //
- // To unwind the stack, we start with a return address and SP for the routine which
- // threw the exception. The next return address can be found by following the
- // back-link at 0(SP) and accessing the saved LR in that frame.
- //
- // Restoring registers is slightly more tricky. If 'saved_CR' is true, we restore
- // the CR from the callers linkage area. For saved GPRs and FPRs we start with
- // the callers SP; the <n> saved FPRs will be at <callers SP> - (8 * <n>) and the
- // <m> saved GPRs will be the (<m> * 4) words ending at at <callers SP> - (8 * <n>)
- // adjusted so that the last word ends on a 16-byte boundary. (See below)
- //
- //
-
- #define __NOSTRING__ // do not include <string>
-
- #include <stdlib.h>
- #include <CPlusLib.h>
- #include <exception.h>
- #include "ExceptionPPC.h"
- #include "NMWException.h"
-
- #if 1
- #define INLINE static // static for debugging
- #else
- #define INLINE inline // inline for shipping code
- #endif
-
- // typedefs
-
- typedef struct ThrowContext {
- double FPR[32]; // FPR0-FPR31 (not all are saved/restored)
- long GPR[32]; // GPR0-GPR31 (not all are saved/restored)
- long CR; // CR0-CR7
- char* SP; // stack pointer during unwind (used for linkage)
- char* FP; // frame pointer during unwind (used for locals)
- char* throwSP; // stack pointer at throw
- char* returnaddr; // return address
- char* throwtype; // throw type argument (0L: rethrow: throw; )
- void* location; // location argument (0L: rethrow: throw; )
- void* dtor; // dtor argument
- CatchInfo *catchinfo; // pointer to rethrow CatchInfo (or 0L)
- } ThrowContext;
-
- typedef struct MWExceptionInfo {
- ExceptionTable* exception_record; // pointer to exception table
- char* current_function; // pointer to current function
- char* action_pointer; // pointer to action
- char* code_section; // base of code section for fragment containing table
- char* data_section; // base of data section for fragment containing table
- char* TOC; // TOC pointer for fragment containing table
- } MWExceptionInfo;
-
- typedef struct FragmentInfo {
- ExceptionTableIndex* exception_start; // start of exception table index for fragment
- ExceptionTableIndex* exception_end; // end of exception table index for fragment
- char* code_start; // start of code section for fragment
- char* code_end; // end of code section for fragment
- char* data_start; // start of data section for fragment
- char* data_end; // end of data section for fragment
- char* TOC; // TOC pointer for fragment
- } FragmentInfo;
-
- typedef struct ActionIterator {
- MWExceptionInfo info; // pointer to exception record
- char* current_SP; // current stack pointer
- char* current_FP; // current frame pointer (SP or R31)
- long current_R31; // current R31
- } ActionIterator;
-
- #define MAXFRAGMENTS 32 // maximum # of code fragments we can register
- static FragmentInfo fragmentinfo[MAXFRAGMENTS];
-
- typedef void (*DeleteFunc)(void *);
-
-
- /************************************************************************/
- /* Purpose..: Register a code fragment and its exception tables */
- /* Input....: pointer to start of fragments code section */
- /* Input....: pointer to end of fragments code section */
- /* Input....: pointer to start of fragments data section */
- /* Input....: pointer to end of fragments data section */
- /* Input....: pointer to start of fragments exception table index */
- /* Input....: pointer to end of fragments exception table index */
- /* Input....: RTOC for fragment */
- /* Return...: unique ID for __ex_unregister_fragment */
- /************************************************************************/
- int __register_fragment(char *code_start, char *code_end,
- char *data_start, char *data_end,
- char *exception_start, char *exception_end,
- char *TOC)
- {
- FragmentInfo *f;
- int i;
-
- // find a free entry in the fragment table
- for(i=0,f=fragmentinfo;i<MAXFRAGMENTS;++i,++f) if(f->code_start==0)
- {
- f->code_start=code_start;
- f->code_end=code_end;
- f->data_start=data_start;
- f->data_end=data_end;
- f->exception_start=(ExceptionTableIndex *)exception_start;
- f->exception_end=(ExceptionTableIndex *)exception_end;
- f->TOC=TOC;
- return(i);
- }
- // couldn't register the fragment
- return(-1);
- }
-
- /************************************************************************/
- /* Purpose..: Un-register a code fragment and its exception tables */
- /* Input....: unique ID assigned in __ex_register_fragment */
- /* Return...: --- */
- /************************************************************************/
- void __unregister_fragment(int fragmentID)
- {
- FragmentInfo *f;
-
- if(fragmentID>=0 && fragmentID<MAXFRAGMENTS)
- {
- f = &fragmentinfo[fragmentID];
- f->code_start=0; f->code_end=0;
- f->data_start=0; f->data_end=0;
- f->exception_start=0; f->exception_end=0;
- f->TOC=0;
- }
- }
-
- /************************************************************************/
- /* Purpose..: Get an exception fragment record pointer */
- /* Input....: pointer to return address */
- /* Return...: pointer to FragmentInfo struct */
- /************************************************************************/
- static FragmentInfo *ExPPC_FindExceptionFragment(char *returnaddr)
- {
- FragmentInfo *f;
- int i;
-
- for(i=0,f=fragmentinfo;i<MAXFRAGMENTS;++i,++f) if(f->code_start!=0)
- {
- if(returnaddr>=f->code_start && returnaddr<f->code_end) return(f);
- }
-
- return(0);
- }
-
- /************************************************************************/
- /* Purpose..: Get a exception record pointer */
- /* Input....: pointer to return address */
- /* Input....: pointer to MWExceptionInfo struct for result */
- /* Return...: --- */
- /************************************************************************/
- static void ExPPC_FindExceptionRecord(char *returnaddr,MWExceptionInfo *info)
- {
- FragmentInfo *fragment;
- ExceptionTableIndex *exceptionindex,*p;
- ExceptionRange *r;
- unsigned long returnoffset,i,m,n;
-
- // so far we haven't found anything
- info->exception_record=0;
- info->action_pointer=0;
-
- // find the exception table for the fragment containing 'returnaddr'
- if ((fragment=ExPPC_FindExceptionFragment(returnaddr))==0) return;
- info->code_section=fragment->code_start;
- info->data_section=fragment->data_start;
- info->TOC=fragment->TOC;
-
- // binary-search the exception table index for a function containing 'returnaddr'
- returnoffset=returnaddr-fragment->code_start;
- exceptionindex=fragment->exception_start;
- for(i=0,n=fragment->exception_end-fragment->exception_start;;)
- {
- if(i>n) return;
- p=&exceptionindex[m=(i+n)/2];
- if(returnoffset<p->functionoffset) n=m-1;
- else if(returnoffset>p->functionoffset+p->functionsize) i=m+1;
- else break;
- }
- info->current_function=fragment->code_start+p->functionoffset;
- info->exception_record=p->directstore?(ExceptionTable *)(&p->exceptionoffset)
- :(ExceptionTable *)(fragment->data_start+p->exceptionoffset);
-
- // find the set of actions to perform for an exception thrown from 'returnaddr'
- returnoffset-=p->functionoffset;
- for(r=info->exception_record->ranges; r->start!=0; r++)
- {
- if(r->start<=returnoffset && r->end>=returnoffset)
- {
- info->action_pointer=(char *)info->exception_record+r->action; break;
- }
- }
- }
-
- /************************************************************************/
- /* Purpose..: Find R31 saved in given stack frame */
- /* Input....: pointer to throw context */
- /* Input....: pointer to topmost exception record */
- /* Return...: pointer to return PC */
- /************************************************************************/
- static long ExPPC_PopR31(char *SP,MWExceptionInfo *info)
- {
- double *FPR_save_area;
- long *GPR_save_area;
- int saved_GPRs, saved_FPRs;
-
- // find saved FPRs
- saved_FPRs=info->exception_record->savedFPRs;
- FPR_save_area=(double *)(SP-saved_FPRs*8);
-
- // find saved GPRs
- saved_GPRs=info->exception_record->savedGPRs;
- GPR_save_area=(long *)FPR_save_area;
- if(saved_FPRs&1) GPR_save_area-=2; // 8-byte gap if # saved FPRs is odd
-
- // return saved R31
- return(GPR_save_area[-1]); // R31 is last register saved, has highest address
- }
-
- /************************************************************************/
- /* Purpose..: Return current exception action type */
- /* Input....: pointer to ActionIterator */
- /* Return...: action type */
- /************************************************************************/
- static exaction_type ExPPC_CurrentAction(const ActionIterator *iter)
- {
- if(iter->info.action_pointer==0) return EXACTION_ENDOFLIST;
- return ((ex_destroylocal *)iter->info.action_pointer)->action&EXACTION_MASK;
- }
-
- /************************************************************************/
- /* Purpose..: Move to next action in Exception Table */
- /* Input....: pointer to ActionIterator */
- /* Return...: next action type */
- /************************************************************************/
- static exaction_type ExPPC_NextAction(ActionIterator *iter)
- {
- exaction_type action;
-
- for(;;)
- {
- if( iter->info.action_pointer==0
- || ((action=((ex_destroylocal *)iter->info.action_pointer)->action)&EXACTION_ENDBIT)!=0 )
- { // end of action list: find next exception record
- char *return_addr, *callers_SP;
-
- // get LR saved in linkage area of caller
- callers_SP=*(char **)iter->current_SP;
- if(iter->info.exception_record->savedGPRs) iter->current_R31=ExPPC_PopR31(callers_SP,&iter->info);
- return_addr=*(char **)(callers_SP+8);
- ExPPC_FindExceptionRecord(return_addr,&iter->info);
- if(iter->info.exception_record==0) terminate(); // cannot find matching exception record
- // pop down to caller's stack frame
- iter->current_SP=callers_SP;
- iter->current_FP=(iter->info.exception_record->hasframeptr)?(char *)iter->current_R31:iter->current_SP;
- if(iter->info.action_pointer==0) continue; // no actions
- }
- else
- {
- switch(action)
- {
- case EXACTION_DESTROYLOCAL:
- iter->info.action_pointer+=sizeof(ex_destroylocal); break;
- case EXACTION_DESTROYLOCALCOND:
- iter->info.action_pointer+=sizeof(ex_destroylocalcond); break;
- case EXACTION_DESTROYLOCALPOINTER:
- iter->info.action_pointer+=sizeof(ex_destroylocalpointer); break;
- case EXACTION_DESTROYLOCALARRAY:
- iter->info.action_pointer+=sizeof(ex_destroylocalarray); break;
- case EXACTION_DESTROYBASE:
- case EXACTION_DESTROYMEMBER:
- iter->info.action_pointer+=sizeof(ex_destroymember); break;
- case EXACTION_DESTROYMEMBERCOND:
- iter->info.action_pointer+=sizeof(ex_destroymembercond); break;
- case EXACTION_DESTROYMEMBERARRAY:
- iter->info.action_pointer+=sizeof(ex_destroymemberarray); break;
- case EXACTION_DELETEPOINTER:
- iter->info.action_pointer+=sizeof(ex_deletepointer); break;
- case EXACTION_DELETEPOINTERCOND:
- iter->info.action_pointer+=sizeof(ex_deletepointercond); break;
- case EXACTION_CATCHBLOCK:
- iter->info.action_pointer+=sizeof(ex_catchblock); break;
- case EXACTION_ACTIVECATCHBLOCK:
- iter->info.action_pointer+=sizeof(ex_activecatchblock); break;
- case EXACTION_SPECIFICATION:
- iter->info.action_pointer+=sizeof(ex_specification)+((ex_specification *)iter->info.action_pointer)->specs*sizeof(void *); break;
- default:
- terminate(); // error
- }
- }
- action=((ex_destroylocal *)iter->info.action_pointer)->action&EXACTION_MASK;
- if(action==EXACTION_BRANCH)
- { // skip to target action--we never return EXACTION_BRANCH to caller!
- iter->info.action_pointer=((char *)iter->info.exception_record)+((ex_branch *)iter->info.action_pointer)->target;
- action=((ex_destroylocal *)iter->info.action_pointer)->action&EXACTION_MASK;
- }
- return action;
- }
- }
-
- /************************************************************************/
- /* Purpose..: Restore registers */
- /* Input....: pointer to throw context */
- /* Input....: pointer to topmost exception record */
- /* Return...: pointer to return PC */
- /************************************************************************/
- static char *ExPPC_PopStackFrame(ThrowContext *context,MWExceptionInfo *info)
- {
- char *SP, *callers_SP;
- double *FPR_save_area;
- long *GPR_save_area;
- int saved_GPRs, saved_FPRs;
- int i, j;
-
- // obtain current and callers frame pointers
- SP=context->SP; callers_SP=*(char **)SP;
-
- // restore saved FPRs
- saved_FPRs=info->exception_record->savedFPRs;
- FPR_save_area=(double *)(callers_SP-saved_FPRs*8);
- for(i=32-saved_FPRs, j=0;i<32;++i,++j) context->FPR[i]=FPR_save_area[j];
-
- // restore saved GPRs
- saved_GPRs=info->exception_record->savedGPRs;
- // GPR_save_area=(long *)(((long)FPR_save_area&0xFFFFFFF0)-saved_GPRs*4);
- // for(i=32-saved_GPRs, j=0;i<32;++i,++j) context->GPR[i]=GPR_save_area[j];
- GPR_save_area=(long *)FPR_save_area;
- if(saved_FPRs&1) GPR_save_area-=2; // 8-byte gap if # saved FPRs is odd
- GPR_save_area-=saved_GPRs;
- for(i=32-saved_GPRs, j=0;i<32;++i,++j) context->GPR[i]=GPR_save_area[j];
-
- // restore saved CR
- if(info->exception_record->savedCR) context->CR=*(long *)(callers_SP+4);
-
- // restore saved SP (back link)
- context->SP=callers_SP;
-
- // return new return_addr
- return(*(char **)(callers_SP+8));
- }
-
- /************************************************************************/
- /* Purpose..: Unwind ex_destroylocal struct */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to throw context */
- /* Input....: pointer to ex_destroylocal struct */
- /* Return...: --- */
- /************************************************************************/
- INLINE void ExPPC_DestroyLocal(ThrowContext *context,const ex_destroylocal *ex)
- {
- DTORCALL_COMPLETE(ex->dtor,context->FP+ex->local);
- }
-
- /************************************************************************/
- /* Purpose..: Unwind ex_destroylocalcond struct */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to throw context */
- /* Input....: pointer to ex_destroylocalcond struct */
- /* Return...: --- */
- /************************************************************************/
- INLINE void ExPPC_DestroyLocalCond(ThrowContext *context,const ex_destroylocalcond *ex)
- {
- int cond = ex->regcond ? (local_cond_type) context->GPR[ex->cond]
- : *(local_cond_type *)(context->FP+ex->cond);
-
- if(cond) DTORCALL_COMPLETE(ex->dtor,context->FP+ex->local);
- }
-
- /************************************************************************/
- /* Purpose..: Unwind ex_destroylocalpointer struct */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to throw context */
- /* Input....: pointer to ex_destroylocalpointer struct */
- /* Return...: --- */
- /************************************************************************/
- INLINE void ExPPC_DestroyLocalPointer(ThrowContext *context,const ex_destroylocalpointer *ex)
- {
- void *pointer = ex->regpointer ? (void *) context->GPR[ex->pointer]
- : *(void **)(context->FP+ex->pointer);
-
- DTORCALL_COMPLETE(ex->dtor,pointer);
- }
-
- /************************************************************************/
- /* Purpose..: Unwind ex_destroylocalarray struct */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to throw context */
- /* Input....: pointer to ex_destroylocalarray struct */
- /* Return...: --- */
- /************************************************************************/
- INLINE void ExPPC_DestroyLocalArray(ThrowContext *context,const ex_destroylocalarray *ex)
- {
- char *ptr = context->FP+ex->localarray;
- long n = ex->elements;
- long size = ex->element_size;
-
- for(ptr=ptr+size*n; n>0; n--)
- {
- ptr-=size; DTORCALL_COMPLETE(ex->dtor,ptr);
- }
- }
-
- /************************************************************************/
- /* Purpose..: Unwind ex_destroymember struct */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to throw context */
- /* Input....: pointer to ex_destroymember struct */
- /* Return...: --- */
- /************************************************************************/
- INLINE void ExPPC_DestroyMember(ThrowContext *context,const ex_destroymember *ex)
- {
- char *objectptr = ex->regpointer ? (char *) context->GPR[ex->objectptr]
- : *(char **)(context->FP+ex->objectptr);
-
- DTORCALL_COMPLETE(ex->dtor,objectptr+ex->offset);
- }
-
- /************************************************************************/
- /* Purpose..: Unwind ex_destroymember struct */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to throw context */
- /* Input....: pointer to ex_destroymember struct */
- /* Return...: --- */
- /************************************************************************/
- INLINE void ExPPC_DestroyBase(ThrowContext *context,const ex_destroymember *ex)
- {
- char *objectptr = ex->regpointer ? (char *) context->GPR[ex->objectptr]
- : *(char **)(context->FP+ex->objectptr);
-
- DTORCALL_PARTIAL(ex->dtor,objectptr+ex->offset);
- }
-
- /************************************************************************/
- /* Purpose..: Unwind ex_destroymembercond struct */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to throw context */
- /* Input....: pointer to ex_destroymembercond struct */
- /* Return...: --- */
- /************************************************************************/
- INLINE void ExPPC_DestroyMemberCond(ThrowContext *context,const ex_destroymembercond *ex)
- {
- char *objectptr = ex->regpointer ? (char *) context->GPR[ex->objectptr]
- : *(char **)(context->FP+ex->objectptr);
- int cond = ex->regcond ? (vbase_ctor_arg_type) context->GPR[ex->cond]
- : *(vbase_ctor_arg_type *)(context->FP+ex->cond);
-
- if(cond) DTORCALL_PARTIAL(ex->dtor,objectptr+ex->offset);
- }
-
- /************************************************************************/
- /* Purpose..: Unwind ex_destroymemberarray struct */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to throw context */
- /* Input....: pointer to ex_destroymemberarray struct */
- /* Return...: --- */
- /************************************************************************/
- INLINE void ExPPC_DestroyMemberArray(ThrowContext *context,const ex_destroymemberarray *ex)
- {
- char *ptr = ex->regpointer ? (char *) context->GPR[ex->objectptr]
- : *(char **)(context->FP+ex->objectptr);
- long n = ex->elements;
- long size = ex->element_size;
-
- for(ptr=ptr+size*n; n>0; n--)
- {
- ptr-=size; DTORCALL_COMPLETE(ex->dtor,ptr);
- }
- }
-
- /************************************************************************/
- /* Purpose..: Unwind ex_deletepointer struct */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to throw context */
- /* Input....: pointer to ex_deletepointer struct */
- /* Return...: --- */
- /************************************************************************/
- INLINE void ExPPC_DeletePointer(ThrowContext *context,const ex_deletepointer *ex)
- {
- char *objectptr = ex->regpointer ? (char *) context->GPR[ex->objectptr]
- : *(char **)(context->FP+ex->objectptr);
-
- ((DeleteFunc) ex->deletefunc)(objectptr);
- }
-
- /************************************************************************/
- /* Purpose..: Unwind ex_deletepointercond struct */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to throw context */
- /* Input....: pointer to ex_deletepointercond struct */
- /* Return...: --- */
- /************************************************************************/
- INLINE void ExPPC_DeletePointerCond(ThrowContext *context,const ex_deletepointercond *ex)
- {
- char *objectptr = ex->regpointer ? (char *) context->GPR[ex->objectptr]
- : *(char **)(context->FP+ex->objectptr);
- int cond = ex->regcond ? (local_cond_type) context->GPR[ex->cond]
- : *(local_cond_type *)(context->FP+ex->cond);
-
- if(cond) ((DeleteFunc) ex->deletefunc)(objectptr);
- }
-
- /************************************************************************/
- /* Purpose..: Unwind stack */
- /* Input....: pointer to throw context */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to topmost action */
- /* Input....: pointer to catcher */
- /* Return...: --- */
- /************************************************************************/
- static void ExPPC_UnwindStack(ThrowContext *context,MWExceptionInfo *info,void *catcher)
- {
- exaction_type action;
-
- #pragma exception_terminate // this will prevent exception exits during unwindind
-
- for(;;)
- {
- if(info->action_pointer==0)
- {
- char *return_addr;
-
- return_addr=ExPPC_PopStackFrame(context,info);
- ExPPC_FindExceptionRecord(return_addr,info);
- if(info->exception_record==0) terminate(); // cannot find matching exception record
- context->FP=(info->exception_record->hasframeptr)?(char *)context->GPR[31]:context->SP;
- continue;
- }
-
- action=((ex_destroylocal *)info->action_pointer)->action;
- switch(action&EXACTION_MASK)
- {
- case EXACTION_BRANCH:
- info->action_pointer=((char *)info->exception_record)+((ex_branch *)info->action_pointer)->target; break;
-
- case EXACTION_DESTROYLOCAL:
- ExPPC_DestroyLocal(context,(ex_destroylocal *)info->action_pointer);
- info->action_pointer+=sizeof(ex_destroylocal); break;
-
- case EXACTION_DESTROYLOCALCOND:
- ExPPC_DestroyLocalCond(context,(ex_destroylocalcond *)info->action_pointer);
- info->action_pointer+=sizeof(ex_destroylocalcond); break;
-
- case EXACTION_DESTROYLOCALPOINTER:
- ExPPC_DestroyLocalPointer(context,(ex_destroylocalpointer *)info->action_pointer);
- info->action_pointer+=sizeof(ex_destroylocalpointer); break;
-
- case EXACTION_DESTROYLOCALARRAY:
- ExPPC_DestroyLocalArray(context,(ex_destroylocalarray *)info->action_pointer);
- info->action_pointer+=sizeof(ex_destroylocalarray); break;
-
- case EXACTION_DESTROYBASE:
- ExPPC_DestroyBase(context,(ex_destroymember *)info->action_pointer);
- info->action_pointer+=sizeof(ex_destroymember); break;
-
- case EXACTION_DESTROYMEMBER:
- ExPPC_DestroyMember(context,(ex_destroymember *)info->action_pointer);
- info->action_pointer+=sizeof(ex_destroymember); break;
-
- case EXACTION_DESTROYMEMBERCOND:
- ExPPC_DestroyMemberCond(context,(ex_destroymembercond *)info->action_pointer);
- info->action_pointer+=sizeof(ex_destroymembercond); break;
-
- case EXACTION_DESTROYMEMBERARRAY:
- ExPPC_DestroyMemberArray(context,(ex_destroymemberarray *)info->action_pointer);
- info->action_pointer+=sizeof(ex_destroymemberarray); break;
-
- case EXACTION_DELETEPOINTER:
- ExPPC_DeletePointer(context,(ex_deletepointer *)info->action_pointer);
- info->action_pointer+=sizeof(ex_deletepointer); break;
-
- case EXACTION_DELETEPOINTERCOND:
- ExPPC_DeletePointerCond(context,(ex_deletepointercond *)info->action_pointer);
- info->action_pointer+=sizeof(ex_deletepointercond); break;
-
- case EXACTION_CATCHBLOCK:
- if(catcher==(void *)info->action_pointer) return; // finished unwinding
- info->action_pointer+=sizeof(ex_catchblock); break;
-
- case EXACTION_ACTIVECATCHBLOCK:
- {
- CatchInfo *catchinfo;
-
- catchinfo=(CatchInfo *)(context->FP+((ex_activecatchblock *)info->action_pointer)->cinfo_ref);
- if(context->catchinfo!=catchinfo && catchinfo->dtor)
- {
- DTORCALL_COMPLETE(catchinfo->dtor,catchinfo->location);
- }
- info->action_pointer+=sizeof(ex_activecatchblock);
- }
- break;
-
- case EXACTION_SPECIFICATION:
- if(catcher==(void *)info->action_pointer) return; // finished unwinding
- info->action_pointer+=sizeof(ex_specification)+((ex_specification *)info->action_pointer)->specs*sizeof(void *);
- break;
-
- default:
- terminate(); // error
- }
- if(action&EXACTION_ENDBIT) info->action_pointer=0;
- }
- }
-
- /************************************************************************/
- /* Purpose..: Check if an exception is in a specification list */
- /* Input....: pointer to exception type string */
- /* Input....: pointer to specification list */
- /* Return...: --- */
- /************************************************************************/
- static int ExPPC_IsInSpecification(char *extype,ex_specification *spec)
- {
- long i,offset;
-
- for(i=0; i<spec->specs; i++)
- {
- if(__throw_catch_compare(extype,spec->spec[i],&offset)) return 1;
- }
- return 0;
- }
-
- /************************************************************************/
- /* Purpose..: Unexpected handler */
- /* Input....: pointer to throw context */
- /* Return...: --- (this function will never return) */
- /************************************************************************/
- extern void __unexpected(CatchInfo* catchinfo)
- {
- ex_specification *unexp=(ex_specification *)catchinfo->stacktop;
-
- #pragma exception_magic
-
- try {
- unexpected();
- }
- catch(...)
- { // unexpected throws an exception => check if the exception matches the specification
- if(ExPPC_IsInSpecification((char *)((CatchInfo *)&__exception_magic)->typeinfo,unexp))
- { // new exception is in specification list => rethrow
- throw;
- }
- if(ExPPC_IsInSpecification("!bad_exception!",unexp))
- { // "bad_exception" is in specification list => throw bad_exception()
- throw bad_exception();
- }
- // cannot handle exception => terminate();
- }
- terminate();
- }
-
- /************************************************************************/
- /* Purpose..: Restore registers and branch to catcher */
- /* Input....: pointer to throw context */
- /* Input....: destination RTOC */
- /* Input....: destination PC */
- /* Return...: --- */
- /************************************************************************/
- static asm void ExPPC_LongJump(register ThrowContext *context, register void *newRTOC, register void *newPC)
- {
- // restore PC (LR)
- mtlr newPC
- // restore RTOC
- mr RTOC,newRTOC
- // restore CR
- lwz r0,context->CR
- mtcrf 255,r0
- // restore R13-R31
- lmw r13,context->GPR[13]
- // restore FP14-FP31
- lfd fp14,context->FPR[14]
- lfd fp15,context->FPR[15]
- lfd fp16,context->FPR[16]
- lfd fp17,context->FPR[17]
- lfd fp18,context->FPR[18]
- lfd fp19,context->FPR[19]
- lfd fp20,context->FPR[20]
- lfd fp21,context->FPR[21]
- lfd fp22,context->FPR[22]
- lfd fp23,context->FPR[23]
- lfd fp24,context->FPR[24]
- lfd fp25,context->FPR[25]
- lfd fp26,context->FPR[26]
- lfd fp27,context->FPR[27]
- lfd fp28,context->FPR[28]
- lfd fp29,context->FPR[29]
- lfd fp30,context->FPR[30]
- lfd fp31,context->FPR[31]
- // restore SP to stack top at throw: discards exception-handling frames
- // but not exception temporaries
- lwz SP,context->throwSP
- // move stack frame back-link from catcher's linkage area to new top of
- // stack; this effectively pops all intermediate frames.
- lwz r3,context->SP
- lwz r3,0(r3)
- stw r3,0(SP)
- // jump to exception handler
- blr
- }
-
- /************************************************************************/
- /* Purpose..: Handle unexpected exception */
- /* Input....: pointer to throw context */
- /* Input....: pointer to topmost MWExceptionInfo struct */
- /* Input....: pointer to specification record */
- /* Return...: --- */
- /************************************************************************/
- static void ExPPC_HandleUnexpected(ThrowContext *context,MWExceptionInfo *info,ex_specification *unexp)
- {
- CatchInfo *catchinfo;
-
- #pragma exception_terminate // this will prevent exception exits during unwinding
-
- ExPPC_UnwindStack(context,info,unexp); // unwind stack to failing specification
-
- // initialize catch info struct
- catchinfo=(CatchInfo *)(context->FP+unexp->cinfo_ref);
- catchinfo->location = context->location;
- catchinfo->typeinfo = context->throwtype;
- catchinfo->dtor = context->dtor;
- catchinfo->stacktop = unexp; // the __unexpected will never call __end_catch
- // so we can resue this field
- // jump to exception handler
- ExPPC_LongJump(context,info->TOC,info->current_function+unexp->pcoffset);
- }
-
- /************************************************************************/
- /* Purpose..: Throw (rethrow) current exception */
- /* Input....: pointer to throw context */
- /* Return...: --- */
- /************************************************************************/
- static void ExPPC_ThrowHandler(ThrowContext *context)
- {
- ActionIterator iter;
- MWExceptionInfo info;
- exaction_type action;
- ex_catchblock *catchblock;
- CatchInfo *catchinfo;
- long offset;
-
- // find first ExceptionRecord
-
- ExPPC_FindExceptionRecord(context->returnaddr, &info);
- if(info.exception_record==0) terminate(); // cannot find matching exception record
- context->FP=(info.exception_record->hasframeptr)?(char *)context->GPR[31]:context->SP;
-
- if(context->throwtype==0)
- { // rethrow, find most recent exception
- iter.info = info;
- iter.current_SP = context->SP;
- iter.current_FP = context->FP;
- iter.current_R31 = context->GPR[31];
- for(action=ExPPC_CurrentAction(&iter);; action=ExPPC_NextAction(&iter))
- {
- switch(action)
- {
- case EXACTION_ACTIVECATCHBLOCK:
- break;
-
- case EXACTION_ENDOFLIST:
- case EXACTION_DESTROYLOCAL:
- case EXACTION_DESTROYLOCALCOND:
- case EXACTION_DESTROYLOCALPOINTER:
- case EXACTION_DESTROYLOCALARRAY:
- case EXACTION_DESTROYBASE:
- case EXACTION_DESTROYMEMBER:
- case EXACTION_DESTROYMEMBERCOND:
- case EXACTION_DESTROYMEMBERARRAY:
- case EXACTION_DELETEPOINTER:
- case EXACTION_DELETEPOINTERCOND:
- case EXACTION_CATCHBLOCK:
- case EXACTION_SPECIFICATION:
- continue;
-
- case EXACTION_TERMINATE:
- default:
- terminate(); // cannot find find most recent exception
- }
- break;
- }
- catchinfo=(CatchInfo *)(iter.current_FP+((ex_activecatchblock *)iter.info.action_pointer)->cinfo_ref);
- context->throwtype = (char *)catchinfo->typeinfo;
- context->location = catchinfo->location;
- context->dtor = catchinfo->dtor;
- context->catchinfo = catchinfo;
- }
- else context->catchinfo=0L;
-
- // find matching exception handler
-
- iter.info = info;
- iter.current_SP = context->SP;
- iter.current_FP = context->FP;
- iter.current_R31 = context->GPR[31];
- for(action=ExPPC_CurrentAction(&iter);; action=ExPPC_NextAction(&iter))
- {
- switch(action)
- {
- case EXACTION_CATCHBLOCK:
- if(__throw_catch_compare(context->throwtype,((ex_catchblock *)iter.info.action_pointer)->catch_type,&offset))
- {
- break;
- }
- continue;
-
- case EXACTION_SPECIFICATION:
- if(!ExPPC_IsInSpecification(context->throwtype,(ex_specification *)iter.info.action_pointer))
- { // unexpected specification
- ExPPC_HandleUnexpected(context,&info,(ex_specification *)iter.info.action_pointer);
- // we will never return from this function call
- }
- continue;
-
- case EXACTION_ENDOFLIST:
- case EXACTION_DESTROYLOCAL:
- case EXACTION_DESTROYLOCALCOND:
- case EXACTION_DESTROYLOCALPOINTER:
- case EXACTION_DESTROYLOCALARRAY:
- case EXACTION_DESTROYBASE:
- case EXACTION_DESTROYMEMBER:
- case EXACTION_DESTROYMEMBERCOND:
- case EXACTION_DESTROYMEMBERARRAY:
- case EXACTION_DELETEPOINTER:
- case EXACTION_DELETEPOINTERCOND:
- case EXACTION_ACTIVECATCHBLOCK:
- continue;
-
- case EXACTION_TERMINATE:
- default:
- terminate(); // cannot find matching catch block
- }
- break;
- }
-
- // we have found a matching catch block
- catchblock=(ex_catchblock *)iter.info.action_pointer;
- ExPPC_UnwindStack(context,&info,catchblock);
-
- // initialize catch info struct
- catchinfo=(CatchInfo *)(context->FP+catchblock->cinfo_ref);
- catchinfo->location = context->location;
- catchinfo->typeinfo = context->throwtype;
- catchinfo->dtor = context->dtor;
- if(*context->throwtype=='*')
- { // pointer match (create a pointer copy with adjusted offset)
- catchinfo->sublocation = &catchinfo->pointercopy;
- catchinfo->pointercopy = *(long *)context->location+offset;
- }
- else
- { // traditional or class match (directly adjust offset)
- catchinfo->sublocation = (char *)context->location+offset;
- }
-
- // remember eventual stacktop (restored from catchinfo at end of catch block)
- // catchinfo->stacktop = context->SP; // saved at try { ... } instead
-
- // jump to exception handler
- ExPPC_LongJump(context,info.TOC,info.current_function+catchblock->catch_pcoffset);
- }
-
- /************************************************************************/
- /* Purpose..: Throw (rethrow) current exception */
- /* Input....: pointer to throw type (0L: rethrow) */
- /* Input....: pointer to complete throw object (0L: rethrow) */
- /* Input....: pointer to throw object destructor (0L: no destructor */
- /* Return...: --- */
- /************************************************************************/
- asm void __throw(char *throwtype, void *location, void *dtor)
- {
- ThrowContext throwcontext;
-
- // allocate a stack frame so we can use symbolic access to locals
- fralloc
- // save GPRs so we can restore them during stack unwind
- stmw r13,throwcontext.GPR[13]
- // save FPRs so we can restore them during stack unwind
- stfd fp14,throwcontext.FPR[14]
- stfd fp15,throwcontext.FPR[15]
- stfd fp16,throwcontext.FPR[16]
- stfd fp17,throwcontext.FPR[17]
- stfd fp18,throwcontext.FPR[18]
- stfd fp19,throwcontext.FPR[19]
- stfd fp20,throwcontext.FPR[20]
- stfd fp21,throwcontext.FPR[21]
- stfd fp22,throwcontext.FPR[22]
- stfd fp23,throwcontext.FPR[23]
- stfd fp24,throwcontext.FPR[24]
- stfd fp25,throwcontext.FPR[25]
- stfd fp26,throwcontext.FPR[26]
- stfd fp27,throwcontext.FPR[27]
- stfd fp28,throwcontext.FPR[28]
- stfd fp29,throwcontext.FPR[29]
- stfd fp30,throwcontext.FPR[30]
- stfd fp31,throwcontext.FPR[31]
- // save CR so we can restore it during stack unwind
- mfcr r3
- stw r3,throwcontext.CR;
- // throwcontext.SP = throwcontext.throwSP = <stack pointer of caller>;
- // throwcontext.returnaddr = <return address into caller>;
- lwz r3,0(sp)
- lwz r4,8(r3)
- stw r3,throwcontext.SP;
- stw r3,throwcontext.throwSP;
- stw r4,throwcontext.returnaddr;
- // throwcontext.throwtype = throwtype;
- lwz r3,throwtype
- stw r3,throwcontext.throwtype
- // throwcontext.location = location;
- lwz r3,location
- stw r3,throwcontext.location
- // throwcontext.dtor = dtor;
- lwz r3,dtor
- stw r3,throwcontext.dtor
- // call __ex_throwhandler(&throwcontext);
- la r3,throwcontext
- bl ExPPC_ThrowHandler
- nop
- // (will never get here)
- frfree
- blr
- }
-
- /************************************************************************/
- /* Purpose..: Deinitialize CatchInfo struct */
- /* Input....: pointer to catchinfo struct */
- /* Return...: --- */
- /************************************************************************/
- void __end__catch(CatchInfo *catchinfo)
- {
- if (catchinfo->location && catchinfo->dtor)
- DTORCALL_COMPLETE(catchinfo->dtor,catchinfo->location);
- }
-